/*
 * Copyright (C) 2011 Wglxy.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tigerlee.candle.activity;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.tigerlee.candle.R;
import com.tigerlee.candle.spreadsheet.MapFeedParedData;
import com.tigerlee.candle.spreadsheet.MapFeedParser;
import com.tigerlee.candle.spreadsheet.MyHttpRequest;
import com.tigerlee.candle.ui.CustomOverlayItem;
import com.tigerlee.candle.ui.MapItemizedOverlay;
import com.tigerlee.candle.util.Constants;
import com.tigerlee.candle.util.SharedPreference;

public class MapProtestActivity extends MapActivity implements OnClickListener,
		android.view.GestureDetector.OnGestureListener {

	private MapView mMapView;
	private MapController mMapController;
	private GeoPoint mCurrentGeoPoint = null;
	private Location mCurrentBestLocation = null;
	private GestureDetector mGestureDetector;
	private LocationListener mNetworkLocationListener;
	private LocationListener mGPSLocationListener;
	private LocationManager mLocationManager;

	private static GeoPoint mPressGeoPoint;

	private SharedPreference mSharedPreference;

	private MyHttpRequest mHttpRequests;

	private static final int DEFAULT_ZOOM = 15;
	
	private static int TIP_DIALOG_ACTIVITY = 1;
	private static int SEND_POST_ACTIVITY = 2;
	private static final int POST_CONFIRM_DAILOG = 3;

	private static final int PROGRESS_DIALOG = 1;
	
	private static final long FIVE_SECONDS = 5 * 1000;
	private static final long ONE_MINUTE = 60 * 1000;

	private static final int OK_FEED_PARSED = 1;
	private static final int FAIL_NO_FEED_DATA = 2;
	private static final int FAIL_CONNECTION_FEED = 3;
	protected static final int TIME_OUT = 4;

	@Override
	protected void onCreate(Bundle icicle) {
		// TODO Auto-generated method stub
		super.onCreate(icicle);
		setContentView(R.layout.map_activity);

		// Get preference to verify whether showing dialog or not
		mSharedPreference = new SharedPreference(getApplicationContext());

		setupMapView();

		// START location listener to get current location by network or GPS
		startLocationListener();

		// Show dialog or not
		if (mSharedPreference.getShowTipDialog() == false) {
			Intent i = new Intent(this, CustomDialogCheckboxActivity.class);
			startActivityForResult(i, TIP_DIALOG_ACTIVITY);
		} else {
			// Create loading dialog
			showDialog(PROGRESS_DIALOG);
		}
		movetoCurrentLocation();

	}

	private void setupMapView() {
		// Setup locationManager to get current location
		this.mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		// Setup your Mapview & Controller
		this.mMapView = (MapView) findViewById(R.id.mapview);
		this.mMapView.setBuiltInZoomControls(true);
		this.mMapView.setClickable(true);
		this.mMapView.setLongClickable(true);

		this.mMapController = this.mMapView.getController();

		// Setup gesture detector to get long click
		this.mGestureDetector = new GestureDetector(this);
	}

	private void startLocationListener() {
		this.mNetworkLocationListener = new LocationListener() {
			public void onStatusChanged(String provider, int status,
					Bundle extras) {
			}

			public void onProviderEnabled(String provider) {
			}

			public void onProviderDisabled(String provider) {

			}

			public void onLocationChanged(Location location) {
				if (isBetterLocation(location)) {
					mCurrentBestLocation = location;
					Double lat;
					Double lng;
					lat = location.getLatitude() * 1E6;
					lng = location.getLongitude() * 1E6;
					mCurrentGeoPoint = new GeoPoint(lat.intValue(),
							lng.intValue());
				}
			}
		};
		mGPSLocationListener = new LocationListener() {
			public void onStatusChanged(String provider, int status,
					Bundle extras) {
			}

			public void onProviderEnabled(String provider) {
			}

			public void onProviderDisabled(String provider) {
			}

			public void onLocationChanged(Location location) {
				if (isBetterLocation(location)) {
					mCurrentBestLocation = location;
					Double lat;
					Double lng;
					lat = location.getLatitude() * 1E6;
					lng = location.getLongitude() * 1E6;
					mCurrentGeoPoint = new GeoPoint(lat.intValue(),
							lng.intValue());
				}
			}
		};
		// Register a listener for location manager.
		mLocationManager.requestLocationUpdates(
				LocationManager.NETWORK_PROVIDER, 0, 0,
				mNetworkLocationListener);

		mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
				0, 0, mGPSLocationListener);
	}

	private void movetoCurrentLocation() {
		// TODO Auto-generated method stub
		if (mCurrentGeoPoint != null) {
			this.mMapController.animateTo(mCurrentGeoPoint);
			this.mMapController.setZoom(DEFAULT_ZOOM);
		} else {
			this.mMapController.setZoom(DEFAULT_ZOOM);
		}
	}

	@Override
	protected void onResume() {
		super.onResume();
		getProtestLocation();
		drawMapMarker();
		movetoCurrentLocation();
	}

	private void getProtestLocation() {
		mHandler.sendMessageDelayed(mHandler.obtainMessage(TIME_OUT),
				FIVE_SECONDS);
		new Thread(new Runnable() {
			public void run() {
				mHttpRequests = new MyHttpRequest();
				InputStream mInputStream = null;
				try {
					mInputStream = mHttpRequests
							.getHttpStream(Constants.mMapFeedUrl);
				} catch (IOException e) {
					e.printStackTrace();
				}
				if (mInputStream != null) {
					mHandler.removeMessages(TIME_OUT);
					MapFeedParser mFeedParser = new MapFeedParser();
					if (mFeedParser.getParedData(mInputStream) == false) {
						// There is no data in the spreadsheet.
						mHandler.sendMessage(mHandler
								.obtainMessage(FAIL_NO_FEED_DATA));
					} else {
						mHandler.sendMessage(mHandler
								.obtainMessage(OK_FEED_PARSED));
					}
				} else {
					// Cannot connect to the spreadsheet.
					mHandler.removeMessages(TIME_OUT);
					mHandler.sendMessage(mHandler
							.obtainMessage(FAIL_CONNECTION_FEED));
				}
			}
		}).start();
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {

		if (requestCode == TIP_DIALOG_ACTIVITY) {
			if (resultCode == RESULT_OK) {
				// Not show dialog anymore..
				mSharedPreference.setShowTipDialog(true);
			}
			showDialog(PROGRESS_DIALOG);
			getProtestLocation();
		}else if(requestCode == SEND_POST_ACTIVITY){
			if(resultCode == RESULT_OK){
				reCreatePressedLocation(data);
			}else{
				removePressedLocation();
			}
			
		}
		else if(requestCode == POST_CONFIRM_DAILOG){
			if(resultCode == RESULT_OK){
				if (mPressGeoPoint != null) {
					Intent i = new Intent(MapProtestActivity.this,
							SendPostLocationActivity.class);
					ArrayList<String> mArrayList = new ArrayList<String>();
					Double mTemp;
					mTemp = mPressGeoPoint.getLatitudeE6() / 1E6;
					mArrayList.add(mTemp.toString());
					mTemp = mPressGeoPoint.getLongitudeE6() / 1E6;
					mArrayList.add(mTemp.toString());
					i.putExtra(Intent.EXTRA_TEXT, mArrayList);
					startActivityForResult(i, SEND_POST_ACTIVITY);
				}
			}else{
				removePressedLocation();
			}
		}
		super.onActivityResult(requestCode, resultCode, data);
	}

	// This method is copied from the android developers site
	// Please refer to
	// http://developer.android.com/guide/topics/location/obtaining-user-location.html
	public boolean isBetterLocation(Location location) {
		if (this.mCurrentBestLocation == null) {
			// New location is always better than no location
			return true;
		}
		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime()
				- this.mCurrentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > ONE_MINUTE;
		boolean isSignificantlyOlder = timeDelta < -ONE_MINUTE;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use
		// the new location
		// because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be
			// worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - this.mCurrentBestLocation
				.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(),
				this.mCurrentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and
		// accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate
				&& isFromSameProvider) {
			return true;
		}
		return false;
	}

	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}

	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			removeDialog(PROGRESS_DIALOG);
			switch (msg.what) {
			case OK_FEED_PARSED:
				drawMapMarker();
				// Move to the best location currently
				break;
			case FAIL_CONNECTION_FEED:
				finishActivity(FAIL_CONNECTION_FEED);
				break;
			case FAIL_NO_FEED_DATA:
				Toast.makeText(getApplicationContext(),
						getString(R.string.toast_fail_no_data),
						Toast.LENGTH_LONG).show();
				break;
			case TIME_OUT:
				break;
			}
		}
	};

	private void drawMapMarker() {
		if (MapFeedParedData.index == 0) {
			return;
		}
		new Thread(new Runnable() {
			public void run() {
				//Clear current map overlay
				if(mMapView.getOverlays()!=null){
					mMapView.getOverlays().clear();
				}
				// Get Map overlays
				List<Overlay> mMapOverlays = mMapView.getOverlays();
				Drawable mDrawable = getResources().getDrawable(
						R.drawable.map_flag);

				// Clear Map overlays
				mMapOverlays.clear();
				
				MapItemizedOverlay mCurrentMapOverlay = new MapItemizedOverlay(
						mDrawable, mMapView);
				for (int i = 0; i < MapFeedParedData.index; i++) {
					Double lat = MapFeedParedData.mLatitudeVector.get(i) * 1E6;
					Double lng = MapFeedParedData.mLongitutdeVector.get(i) * 1E6;
					GeoPoint mGeoPoint = new GeoPoint(lat.intValue(),
							lng.intValue());
					mCurrentMapOverlay.addOverlay(new CustomOverlayItem(
							mGeoPoint, MapFeedParedData.mTitleVector.get(i),
							MapFeedParedData.mDescriptionVector.get(i),
							getString(R.string.text_by) + " "
									+ MapFeedParedData.mNickNameVector.get(i)));
					mMapOverlays.add(mCurrentMapOverlay);
				}				
			}

		}).start();
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case PROGRESS_DIALOG:
			ProgressDialog dialog = new ProgressDialog(this);
			dialog.setMessage(getString(R.string.text_loading_dialog));
			dialog.setIndeterminate(true);
			dialog.setCancelable(false);
			return dialog;
		default:
			break;
		}
		return super.onCreateDialog(id);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		// make go to long press.
		int action = event.getAction();
		// GestureDetector will be invoked only press down.
		if (!(action > 4)) {
			// Detect Long press event by Gesture detector
			this.mGestureDetector.onTouchEvent(event);
		}
		return super.dispatchTouchEvent(event);
	}

	public void onLongPress(MotionEvent e) {
		// Make a vibrator with a dialog
		Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
		vibe.vibrate(100);
		mPressGeoPoint = this.mMapView.getProjection().fromPixels(
				(int) e.getX()+10, (int) e.getY()-30);
		drawPressedLocation(null,null,null);
		showPostConfirmDialog();
	}

	private void showPostConfirmDialog() {
		Intent i = new Intent(this, CustomDialogButtonActivity.class);
		i.putExtra(Intent.EXTRA_TEXT, getString(R.string.text_post_dialog));
		startActivityForResult(i, POST_CONFIRM_DAILOG);
	}

	private void drawPressedLocation(String title, String name, String description) {
		// TODO Auto-generated method stub
		List<Overlay> mMapOverlays = mMapView.getOverlays();
		Drawable mDrawable = getResources().getDrawable(
				R.drawable.map_flag);
		
		MapItemizedOverlay mCurrentMapOverlay = new MapItemizedOverlay(
				mDrawable, mMapView);
		if(title != null && name != null && description != null){
			removePressedLocation();
			mCurrentMapOverlay.addOverlay(new CustomOverlayItem(mPressGeoPoint, title, name, description));
		}else{
			mCurrentMapOverlay.addOverlay(new CustomOverlayItem(mPressGeoPoint, "", "", ""));
		}
		
		mMapOverlays.add(mCurrentMapOverlay);
	}
	private void removePressedLocation(){
		List<Overlay> mMapOverlays = mMapView.getOverlays();
		mMapOverlays.remove(mMapOverlays.size()-1);
	}
	private void reCreatePressedLocation(Intent i){
		ArrayList<String> mPassedArray = new ArrayList<String>();
		mPassedArray = i.getStringArrayListExtra(Intent.EXTRA_TEXT);
		drawPressedLocation(mPassedArray.get(0),mPassedArray.get(1),mPassedArray.get(2));
		
	}

	public void finishActivity() {
		Toast.makeText(this, getString(R.string.toast_fail_no_connection),
				Toast.LENGTH_LONG).show();
		finish();
	}
	@Override
	protected void onRestart() {
		// TODO Auto-generated method stub
		super.onRestart();
	}

	@Override
	protected void onDestroy() {
		if (this.mNetworkLocationListener != null) {
			this.mLocationManager.removeUpdates(mNetworkLocationListener);
		}
		if (this.mGPSLocationListener != null) {
			this.mLocationManager.removeUpdates(mGPSLocationListener);
		}
		super.onDestroy();
	}

	// Not use overrided methods on below
	public boolean onDown(MotionEvent e) {
		// TODO Auto-generated method stub
		return false;
	}

	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {
		// TODO Auto-generated method stub
		return false;
	}

	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {
		// TODO Auto-generated method stub
		return false;
	}

	public void onShowPress(MotionEvent e) {
		// TODO Auto-generated method stub

	}

	public boolean onSingleTapUp(MotionEvent e) {
		// TODO Auto-generated method stub
		return false;
	}

	public void onClick(View v) {
		// TODO Auto-generated method stub
	}

	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}
}
